/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package chatlink;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 *
 * @author Nguyen Van Thoi
 */
public class ServerForm extends MyEvent {

    private ServerSocket _serverSck = null;
    private ObjectInputStream _ois = null;
    private ObjectOutputStream _oos = null;
    private Socket _clientSck;
    private JFrame _jServerForm;
    private JTextArea _jtxtMessage;
    private JScrollPane _jscrollUsers, _jscrollClientMessage;
    private JList<Object> _jlstOnline;
    private Map<String, Socket> _users;
    private JButton _jbtnStop;
    private JPanel _jPanel;
    private final int PORT = 9999;

    public ServerForm() throws IOException {

        _jServerForm = new JFrame("Server");
        _users = new HashMap<>();
        _jlstOnline = new JList<>();

        _jtxtMessage = new JTextArea(20, 31);
        _jtxtMessage.setBackground(Color.DARK_GRAY);
        _jtxtMessage.setForeground(Color.GREEN);
        _jtxtMessage.setLineWrap(true);
        _jtxtMessage.setEditable(false);

        _jscrollClientMessage = new JScrollPane(_jtxtMessage);
        _jscrollUsers = new JScrollPane(_jlstOnline);
        _jscrollUsers.setPreferredSize(new Dimension(120, 320));


        _jbtnStop = new JButton("Stop");
        _jbtnStop.setPreferredSize(new Dimension(420, 30));
        _jPanel = new JPanel();
    }

    public void CreateGUI() {
        _jPanel.add(_jscrollClientMessage);
        _jPanel.add(_jscrollUsers);
        _jPanel.add(_jbtnStop);
        _jServerForm.add(_jPanel);
        _jServerForm.setSize(500, 420);
        _jServerForm.setVisible(true);
        _jServerForm.setResizable(false);
        _jServerForm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void RunServer() throws IOException, ClassNotFoundException {
        _serverSck = new ServerSocket(PORT);
        _jtxtMessage.append("Server is start!\n");

        while (true) {
            _clientSck = _serverSck.accept();
            _oos = new ObjectOutputStream(_clientSck.getOutputStream());

            Message message = new Message();
            message.setStatus(MessageType.NULL);
            StreamData.WriteObject(_oos, message);

            _ois = new ObjectInputStream(_clientSck.getInputStream());
            message = (Message) _ois.readObject();

            DataAccess da = new DataAccess();
            Account accountInfo = null;
            switch (message.getMessage()) {
                case "Login":
                    accountInfo = (Account) _ois.readObject();
                    try {
                        message = new Message();
                        Account result = da.MemberLogin(accountInfo);
                        if (result.getAccountId().equals(accountInfo.getAccountId())
                                && result.getPassword().equals(accountInfo.getPassword())) {
                            if (IsOnline(accountInfo)) {
                                message.setMessage("Account was online! Can't login again!");
                                message.setStatus(MessageType.LOGIN_FAILED);
                                break;
                            }
                            _users.put(accountInfo.getAccountId(), _clientSck);
                            _jlstOnline.setListData(_users.keySet().toArray());
                            StreamData.WriteObject(_oos, _users.keySet().toArray());

                            message.setMessage("Welcome to ChatLink!");
                            message.setStatus(MessageType.LOGIN_SUCCESSFULLY);
                            StreamData.WriteObject(_oos, message);

                            Thread t = new ServerThread();
                            t.start();

                            _jtxtMessage.append(accountInfo.getAccountId() + " connected!\n");
                        } else {
                            message.setMessage("Account information not found! Please try again!");
                            message.setStatus(MessageType.LOGIN_FAILED);
                            StreamData.WriteObject(_oos, message);
                        }

                    } catch (ClassNotFoundException | SQLException ex) {
                        Logger.getLogger(ServerForm.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    break;
                case "Register":
                    accountInfo = (Account) _ois.readObject();
                    try {
                        message = new Message();
                        if (da.Register(accountInfo)) {
                            message.setMessage("Register successfully!");
                            message.setStatus(MessageType.REGISTER_SUCCESSFULLY);
                            _jtxtMessage.append(accountInfo.getAccountId() + " register!\n");
                            StreamData.WriteObject(_oos, message);
                        } else {
                            message.setMessage("Register not successfully!");
                            message.setStatus(MessageType.REGISTER_FAILED);
                            StreamData.WriteObject(_oos, message);
                        }
                    } catch (ClassNotFoundException | SQLException ex) {
                        Logger.getLogger(ServerForm.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    break;
            }
        }
    }

    private boolean IsOnline(Account accountInfo) {
        for (Map.Entry<String, Socket> user : _users.entrySet()) {
            if (user.getKey().equals(accountInfo.getAccountId())) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ServerForm serverFrm = new ServerForm();
        serverFrm.CreateGUI();
        try {
            serverFrm.RunServer();
        } catch (BindException e) {
            JOptionPane.showMessageDialog(null, "Server đang chạy. Tự động đóng!");
            System.exit(1);
        }

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource().equals(_jbtnStop)) {
        }
    }

    class ServerThread extends Thread {

        @Override
        public void run() {
            String userOffline = "";

            try {
                Message message = new Message();
                while ((message = (Message) StreamData.ReadObject(_ois)) != null) {
                    if (message.getStatus().equals(MessageType.USER_OFFLINE)) {
                        userOffline = message.getMessage();
                        _users.remove(userOffline);
                        _jlstOnline.setListData(_users.keySet().toArray());
                        _jtxtMessage.append(userOffline + " offline!\n");
                        _oos.close();
                        _ois.close();
                        _clientSck.close();
                        return;
                    }
                    StreamData.WriteObject(_oos, message);
                    _jtxtMessage.append(message.getMessage() + "\n");
                }
            } catch (SocketException ex) {
                _jtxtMessage.append("");
                _users.remove(userOffline);
                _jlstOnline.setListData(_users.keySet().toArray());
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}
